<?php

namespace App\Http\Controllers;

use App\Entity\UserEntity;
use App\Entity\WechatUserEntity;
use App\Events\Sms\VerifyCodeEvent;
use App\Models\User;
use App\Models\WechatUser;
use App\Services\Cache\Key;
use App\Services\Code\HttpResponse;
use App\Services\SmsVerifyCodeService;
use App\Services\WechatService;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class LoginController extends BaseController
{
    //渠道
    public const CHANNEL_ID = 0;

    /**
     * 使用code获取openid和session-key,token
     *
     * @api {get} /openid 获取openid和user
     * @apiVersion 1.0.0
     * @apiName openid
     * @apiGroup Wechat
     * @apiDescription 使用code获取openid和user
     *
     * @apiParam {string} code code
     *
     * @apiSuccessExample {json} success-未注册:
     *     {"code":200,"message":"success","data":{"wechat":{"session_key":"8oMtjtz1XVJyHSnI7rmmIA==","openid":"oRNFL5M_w84TGyVzbLVx6lCyg0N4"},"user":null,"registered":false}}
     * @apiSuccessExample {json} success-已注册:
     *     {"code":200,"message":"success","data":{"wechat":{"session_key":"8oMtjtz1XVJyHSnI7rmmIA==","openid":"oRNFL5M_w84TGyVzbLVx6lCyg0N4"},"user":{"id":255,"name":"vector","password":"","phone":"15101575451","phone_verified_at":"2019-12-30 15:19:11","last_login_at":"2020-08-06 19:56:24","openid":"oVCNz0aPkdvA3e0d3AuHRwel3z_c","enabled":1,"created_at":"2019-12-30 15:19:11","updated_at":"2020-08-06 19:56:24","user_channelid":0},"registered":true}}
     * @apiErrorExample {json} fail:
     *     {"code":1200,"message":"code empty"}
     */
    public function openid()
    {
        $code = request()->input('code');
        if (empty($code)) {
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_WECHAT_CODE_EMPTY, 'code empty'));
        }
        try {
            $sess = WechatService::getMiniProgramSession($code);
            if (empty($sess['openid'])) {
                throw new \Exception('获取openid异常');
            }

            $openid = $sess['openid'];

            // 取用户信息
            $wechatUserEntity = WechatUserEntity::findByOpenid($openid);
            $user             = null;
            if ($wechatUserEntity && $userEntity = UserEntity::find($wechatUserEntity->getUserId())) {
                $user = $userEntity->toArray();
            }

            return response()->json(HttpResponse::respSuccess(HttpResponse::CODE_SUCCESS, ['wechat' => $sess, 'user' => $user, 'registered' => (bool) $user]));
        } catch (\Throwable $e) {
            logException($e);

            return response()->json(HttpResponse::respFail(HttpResponse::CODE_WECHAT_SESSION_ERR, '获取openid异常'));
        }
    }

    /**
     * 获取验证码
     *
     * @api {post} /verify 获取验证码
     * @apiVersion 1.0.0
     * @apiName verify
     * @apiGroup User
     * @apiDescription 获取验证码
     *
     * @apiParam {string} phone 手机号
     *
     * @apiSuccessExample {json} success:
     *     {"code":200,"message":"success","data":{"code":1234}}
     * @apiErrorExample {json} fail:
     *     {"code":1301,"message":"验证码不能重复发送"}
     */
    public function verify()
    {
        $phone = request()->input('phone');
        $cache = Key::getMiniLoginVerify($phone);
        $ttl   = Key::getMiniLoginVerifyTtl($phone);
        if (Redis::get($ttl)) {
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_VERIFY_REDO, '验证码不能重复发送'));
        }
        $verifyCode = '123456';
        if (prod()) {
            $verifyCode = SmsVerifyCodeService::generateStr(6, true);
            event(new VerifyCodeEvent($phone, $verifyCode));
        }
        Log::info('用户登陆验证码:' . $verifyCode);

        Redis::setex($ttl, 30, $verifyCode);
        Redis::setex($cache, 600, $verifyCode);

        return response()->json(HttpResponse::respSuccess(HttpResponse::CODE_SUCCESS, ['code' => $verifyCode]));
    }

    /**
     * 登陆|注册
     *
     * @return \Illuminate\Http\JsonResponse
     *
     * @api {POST} /login 登陆|注册
     * @apiVersion 1.0.0
     * @apiName login
     * @apiGroup User
     * @apiDescription 用户注册或者登陆
     *
     * @apiParam {string} phone 手机号
     * @apiParam {string} verify 验证码
     * @apiParam {string} openid 微信openid
     * @apiParam {string} [nickname] 微信昵称
     * @apiParam {string} [headimgurl] 微信头像
     *
     * @apiSuccessExample {json} success:
     *     {"code":200,"message":"success","data":{"user":{"id":255,"name":"vector","password":"","phone":"15101575451","phone_verified_at":"2019-12-30 15:19:11","last_login_at":"2020-08-06 19:56:24","openid":"oVCNz0aPkdvA3e0d3AuHRwel3z_c","enabled":1,"created_at":"2019-12-30 15:19:11","updated_at":"2020-08-06 19:56:24","user_channelid":0},"wechat":{"id":255,"openid":"oVCNz0aPkdvA3e0d3AuHRwel3z_c","nickname":"vector","sex":"","language":"","city":"","province":"","country":"","headimgurl":"","privilege":"","unionid":"","user_id":255,"enabled":1,"created_at":"2019-12-30 15:19:11","updated_at":"2019-12-30 15:19:11","channelid":0}}}
     * @apiErrorExample {json} fail:
     *     {"code":1100,"message":"phone or openid err"}
     */
    public function login()
    {
        Log::info('request params', request()->input());

        $phone      = request()->input('phone');
        $verify     = request()->input('verify');
        $openid     = request()->input('openid');
        $nickname   = request()->input('nickname', '');
        $headimgurl = request()->input('headimgurl', '');

        if (!$phone || !$verify || !$openid) {
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_PARAMS_ERR, 'phone or openid or verify empty'));
        }

        $cache       = Key::getMiniLoginVerify($phone);
        $cacheVerify = Redis::get($cache);
        if (empty($cacheVerify)) {
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_VERIFY_TIMEOUT, '验证码已过期'));
        }
        if ($verify !== $cacheVerify) {
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_VERIFY_ERROR, '验证码错误'));
        }

        DB::beginTransaction();

        try {
            $isNew = false;
            $usersEntity = UserEntity::findByPhone($phone);
            if (empty($usersEntity)) {
                $isNew = true;
                $usersEntity = new UserEntity(new User());
                $usersEntity->setCreateAt(Carbon::now()->getTimestamp());
                $usersEntity->setPhone($phone);
                $usersEntity->setPhoneVerifiedAt(Carbon::now()->toDateTimeString());
            }
            $usersEntity->setUserChannelid(self::CHANNEL_ID);
            $usersEntity->setOpenid($openid);
            $usersEntity->setName($nickname);
            $usersEntity->setLastLoginAt(Carbon::now()->toDateTimeString());
            $usersEntity->save();

            if ($isNew) {
                Log::info('新增用户', $usersEntity->toArray());
            } else {
                Log::info('迁移用户信息', $usersEntity->toArray());
            }

            $wechatUserEntity = WechatUserEntity::findByOpenid($openid);
            if (empty($wechatUserEntity)) {
                $wechatUserEntity = new WechatUserEntity(new WechatUser());
                $wechatUserEntity->setCreatedAt(Carbon::now()->toDateTimeString());
            }
            $wechatUserEntity->setOpenid($openid);
            $wechatUserEntity->setHeadimgurl($headimgurl);
            $wechatUserEntity->setChannelid(self::CHANNEL_ID);
            $wechatUserEntity->setEnabled(1);
            $wechatUserEntity->setNickname($nickname);
            $wechatUserEntity->setUserId($usersEntity->getUserId());
            $wechatUserEntity->save();

            //提交事务
            DB::commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            logException($e);
            return response()->json(HttpResponse::respFail(HttpResponse::CODE_FAIL, '登录异常，请联系技术人员！'));
        }

        Redis::del($cache);

        $user = [
            'user'   => $usersEntity->toArray(),
            'wechat' => $wechatUserEntity->toArray(),
        ];

        return response()->json(HttpResponse::respSuccess(HttpResponse::CODE_SUCCESS, $user));
    }
}
